cmake_minimum_required(VERSION 3.16)
project(cem LANGUAGES CXX)

# 生成 compile_commands.json 便于 IDE 索引
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# 默认构建类型
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

# 使用 C++17（按用户要求）
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(ENV{LIBMESH_DIR} "/home/one/app/libmesh-1.9.0")
set(ENV{CJSON_DIR} "/home/one/app/cJSON-1.7.19")
set(ENV{GTEST_DIR} "/home/one/app/googletest-1.17.0")
set(ENV{PKG_CONFIG_PATH} "$ENV{LIBMESH_DIR}/lib/pkgconfig:$ENV{CJSON_DIR}/lib/pkgconfig:$ENV{GTEST_DIR}/lib/pkgconfig")
find_package(PkgConfig REQUIRED)
find_package(MPI REQUIRED)

set(LIBMESH_FOUND FALSE)
pkg_check_modules(LIBMESH REQUIRED libmesh)
if(NOT LIBMESH_FOUND)
  message(FATAL_ERROR "找不到 libMesh 的 pkg-config 包。请安装 libmesh.pc 或设置 PKG_CONFIG_PATH。")
endif()

# 聚合 libMesh 的编译/包含/链接信息为 INTERFACE 目标
add_library(libmesh_flags INTERFACE)
# 编译与包含
target_compile_options(libmesh_flags INTERFACE ${LIBMESH_CFLAGS_OTHER})
target_include_directories(libmesh_flags INTERFACE ${LIBMESH_INCLUDE_DIRS})
# 链接：库目录、库与额外链接选项
if(LIBMESH_LIBRARY_DIRS)
  target_link_directories(libmesh_flags INTERFACE ${LIBMESH_LIBRARY_DIRS})
endif()
# 链接 libMesh 提供的库
target_link_libraries(libmesh_flags INTERFACE ${LIBMESH_LIBRARIES})
# 通过 CMake 的 MPI 导入目标传递 MPI 依赖
target_link_libraries(libmesh_flags INTERFACE MPI::MPI_CXX)
if(LIBMESH_LDFLAGS_OTHER)
  target_link_options(libmesh_flags INTERFACE ${LIBMESH_LDFLAGS_OTHER})
endif()

# 检查 libMesh 是否支持 VTK（不支持则直接中断）
include(CheckCXXSourceCompiles)
set(_SAVE_REQ_FLAGS     "${CMAKE_REQUIRED_FLAGS}")
set(_SAVE_REQ_INCLUDES  "${CMAKE_REQUIRED_INCLUDES}")
set(CMAKE_REQUIRED_FLAGS    "${LIBMESH_CFLAGS}")
set(CMAKE_REQUIRED_INCLUDES "${LIBMESH_INCLUDE_DIRS}")
check_cxx_source_compiles("#include <libmesh/libmesh_config.h>\n#ifdef LIBMESH_HAVE_VTK\nint main(){return 0;}\n#else\n#error no vtk\n#endif\n" LIBMESH_HAVE_VTK)
set(CMAKE_REQUIRED_FLAGS    "${_SAVE_REQ_FLAGS}")
set(CMAKE_REQUIRED_INCLUDES "${_SAVE_REQ_INCLUDES}")
if(NOT LIBMESH_HAVE_VTK)
  message(FATAL_ERROR "libMesh 未启用 VTK，请以开启 VTK 的方式重建 libMesh 后重试。")
endif()

# cJSON（仅通过 pkg-config)
set(CJSON_FOUND FALSE)
pkg_check_modules(CJSON REQUIRED libcjson)
if(NOT CJSON_FOUND)
  message(FATAL_ERROR "找不到 cjson 的 pkg-config 包。请安装 libcjson.pc 或设置 PKG_CONFIG_PATH。")
endif()

# cem_core 静态库（工程脚手架主体）
add_library(cem_core STATIC
  src/mesh_manager.cpp
  src/parameter_reader.cpp
  src/material_database.cpp
  src/boundary_condition.cpp
  src/electromagnetics_system.cpp
  src/assembler.cpp
  src/solver_manager.cpp
  src/post_processor.cpp
  src/io_manager.cpp
  src/config_directory.cpp
  src/json_config_builder.cpp
  src/material_utils.cpp
  src/boundary_condition_utils.cpp
  src/material_law_legacy.cpp
  src/boundary_condition_object.cpp
)

target_include_directories(cem_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
# 继承 libMesh 的编译/链接信息
target_link_libraries(cem_core PUBLIC libmesh_flags)
# 启用 cJSON（若通过 pkg-config 找到）
if(CJSON_FOUND)
  target_include_directories(cem_core PUBLIC ${CJSON_INCLUDE_DIRS})
  if(CJSON_LIBRARY_DIRS)
    target_link_directories(cem_core PUBLIC ${CJSON_LIBRARY_DIRS})
  endif()
  target_link_libraries(cem_core PUBLIC ${CJSON_LIBRARIES})
  if(CJSON_LDFLAGS_OTHER)
    target_link_options(cem_core PUBLIC ${CJSON_LDFLAGS_OTHER})
  endif()
endif()

# 可执行文件
add_executable(cem app/mtsz_minimal.cpp)
add_executable(poisson_demo app/poisson_demo.cpp)

# 主程序与示例链接核心与依赖
target_link_libraries(cem PRIVATE cem_core)
target_link_libraries(poisson_demo PRIVATE libmesh_flags)

# CTest（直接单进程运行，保持简洁）
include(CTest)
if(BUILD_TESTING)
  add_test(NAME poisson_np1 COMMAND $<TARGET_FILE:poisson_demo>)
  add_test(NAME m2_1d_load COMMAND $<TARGET_FILE:cem> --mesh ${CMAKE_CURRENT_SOURCE_DIR}/example/case1/3D.msh)
  add_test(NAME m2_1d_input_load COMMAND $<TARGET_FILE:cem> --mesh ${CMAKE_CURRENT_SOURCE_DIR}/example/case1/3D.msh --config ${CMAKE_CURRENT_SOURCE_DIR}/example/case1/input.json)

  set(GTEST_FOUND FALSE)
  pkg_check_modules(GTEST REQUIRED gtest)
  if(NOT GTEST_FOUND)
    message(FATAL_ERROR "找不到 googletest 的 pkg-config 包。请安装 libgtest.pc 或设置 PKG_CONFIG_PATH。")
  else()
    add_executable(test_parameter_reader tests/test_parameter_reader.cpp)
    target_link_libraries(test_parameter_reader PRIVATE cem_core ${GTEST_LIBRARIES})
    target_link_directories(test_parameter_reader PRIVATE ${GTEST_LIBRARY_DIRS})
    target_include_directories(test_parameter_reader PRIVATE ${GTEST_INCLUDE_DIRS})
    target_compile_definitions(test_parameter_reader PRIVATE PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}")

    add_test(NAME parameter_reader_basic COMMAND test_parameter_reader)

    # 合并: ParameterReader 边界组/边界条件解析测试已合并入 test_parameter_reader
    # 通过 gtest_filter 运行对应测试用例
    add_test(NAME parameter_reader_boundary COMMAND test_parameter_reader --gtest_filter=ParameterReaderBoundaryTest.*)

    # 新增: SolverManager 零右端项路径单测
    add_executable(test_solver_manager tests/test_solver_manager.cpp)
    target_link_libraries(test_solver_manager PRIVATE cem_core ${GTEST_LIBRARIES})
    target_link_directories(test_solver_manager PRIVATE ${GTEST_LIBRARY_DIRS})
    target_include_directories(test_solver_manager PRIVATE ${GTEST_INCLUDE_DIRS})
    add_test(NAME solver_manager_zero_rhs COMMAND test_solver_manager)

    # 新增: PostProcessor 基本日志与 VTK 写出单测
    add_executable(test_post_processor tests/test_post_processor.cpp)
    target_link_libraries(test_post_processor PRIVATE cem_core ${GTEST_LIBRARIES})
    target_link_directories(test_post_processor PRIVATE ${GTEST_LIBRARY_DIRS})
    target_include_directories(test_post_processor PRIVATE ${GTEST_INCLUDE_DIRS})
    add_test(NAME post_processor_io COMMAND test_post_processor)

    # 新增: 旋转一致性测试（角度加 360° 不改变矩阵作用结果）
    add_executable(test_rotation_consistency tests/test_rotation_consistency.cpp)
    target_link_libraries(test_rotation_consistency PRIVATE cem_core ${GTEST_LIBRARIES})
    target_link_directories(test_rotation_consistency PRIVATE ${GTEST_LIBRARY_DIRS})
    target_include_directories(test_rotation_consistency PRIVATE ${GTEST_INCLUDE_DIRS})
    target_compile_definitions(test_rotation_consistency PRIVATE PROJECT_SOURCE_DIR="${CMAKE_SOURCE_DIR}")
    add_test(NAME rotation_consistency COMMAND test_rotation_consistency)
  endif()
endif()

# 编译告警
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
  target_compile_options(cem PRIVATE -Wall -Wextra -Wpedantic)
  target_compile_options(cem_core PRIVATE -Wall -Wextra -Wpedantic)
endif()